/*
 * @Author: yuluo
 * @Date: 2025-07-02
 * @LastEditors: yuluo
 * @LastEditTime: 2025-09-06
 * @FilePath: \Projecte:\gitee\GD32F427\gd32-f427-BootLoader\App\src\io_lib.c
 * @Description:
 * 如有特殊注意事项请填写
 * Copyright (c) by ${yuluo}, All Rights Reserved.
 */

#include "io_lib.h"

/* 可换成链表动态注册 */
/* 设备列表 */
static io_device_t *dev_table[DEVICE_MAX];
/* 设备列表计数 */
static uio8_t device_count = 0;
/* 系统时间 */
static uio32_t sys_time = 0;
static volatile uio8_t tick_irq_flag;

/**
 * @LastEditTime: Do not edit
 * @Description: 简单的字符串比较函数
 * @param {io8_t} *s1
 * @param {io8_t} *s2
 * @return {uio8_t} 字符串相等时返回0
 */
static uio8_t io_compare_str(const io8_t *s1, const io8_t *s2)
{
    while (*s1 && (*s1 == *s2))
    {
        s1++;
        s2++;
    }
    return (uio8_t)*s1 - (uio8_t)*s2;
}

/**
 * @LastEditTime: Do not edit
 * @Description: 设备初始化化
 * @param {io_device_t} *dev
 * @return {}
 */
static void io_device_init(io_device_t *dev)
{
    if (dev && dev->drv && dev->drv->init)
    {
        dev->drv->init();
    }
    else
    {
        PRINT_ERR("device is not initialized");
    }
}

/**
 * @LastEditTime: Do not edit
 * @Description: 设备使能输出
 * @param {io_device_t} *dev
 * @return {}
 */
static void io_device_enable(io_device_t *dev)
{
    if (dev && dev->drv && dev->drv->io_enable)
    {
        dev->drv->io_enable();
    }
    else
    {
        PRINT_ERR("device has no output high function");
    }
}

/**
 * @LastEditTime: Do not edit
 * @Description: 是被失能输出
 * @param {io_device_t} *dev
 * @return {}
 */
static void io_device_disable(io_device_t *dev)
{
    if (dev && dev->drv && dev->drv->io_disable)
    {
        dev->drv->io_disable();
    }
    else
    {
        PRINT_ERR("device has no output low function");
    }
}

/**
 * @LastEditTime: Do not edit
 * @Description: 通过设备名称查找对应的设备地址
 * @param {io8_t} *name
 * @return {io_operation_t*} 设备在列表中的地址
 */
static io_operation_t *io_device_found(const io8_t *name)
{
    uio8_t i = 0;
    for (i = 0; i < device_count; i++)
    {
        if (io_compare_str(name, dev_table[i]->type) == 0)
        {
            return dev_table[i]->drv;
        }
    }
    PRINT_ERR("device is not found");
    return io_ptr;
}

/**
 * @LastEditTime: Do not edit
 * @Description: 每隔设备具体的轮询任务
 * @param {io_device_t} *dev
 * @return {}
 */
static void io_run_function(io_device_t *dev)
{
    /* 当前时间戳 */
    uio32_t now_time;

    /* 不开启或者空闲时退出 */
    if (dev->drv->io_open == IO_FALSE || dev->drv->state == IO_IDEL)
        return;

    /* 先获取当前的时间戳 */
    now_time = io_tick_get();

    switch (dev->drv->state)
    {
    case IO_IDEL:
        /* 空闲不管 */
        break;

    case IO_WAIT_START:
        /* 当前时间戳-设置参数时的时间戳大于等待时间时才开启 */
        if ((uio32_t)(now_time - dev->drv->last_tick) > dev->drv->wait_time)
        {
            dev->drv->io_enable();
            dev->drv->last_tick = now_time;
            dev->drv->state = IO_ENABLE;
        }
        break;

    case IO_ENABLE:
        /* 关闭时间为0时就一直开启 */
        if (dev->drv->disable_time != 0)
        {
            /* 当前时间戳-设置参数时的时间戳大于开启时间时关闭 */
            if ((uio32_t)(now_time - dev->drv->last_tick) > dev->drv->enable_time)
            {
                dev->drv->io_disable();
                dev->drv->last_tick = now_time;
                dev->drv->state = IO_DISABLE;
            }
        }
        break;

    case IO_DISABLE:
        /* 当前时间戳-设置参数时的时间戳大于关闭时间时判断 */
        if ((uio32_t)(now_time - dev->drv->last_tick) > dev->drv->disable_time)
        {
            /* 是否是无限循环蜂鸣 */
            if (dev->drv->loop_count == IO_OUTPUT_LOOP)
            {
                /* 无限循环蜂鸣就举行开启 */
                dev->drv->io_enable();
                dev->drv->last_tick = now_time;
                dev->drv->state = IO_ENABLE;
            }
            else
            {
                /* 不是无限循环蜂鸣就判断蜂鸣次数 */
                dev->drv->current_count++;
                if (dev->drv->current_count > dev->drv->loop_count)
                {
                    dev->drv->state = IO_DONE;
                }
                else
                {
                    dev->drv->io_enable();
                    dev->drv->last_tick = now_time;
                    dev->drv->state = IO_ENABLE;
                }
            }
        }
        break;

    case IO_DONE:
        /* 任务完成保持关闭 */
        dev->drv->io_disable();
        dev->drv->state = IO_IDEL;
        break;

    default:
        break;
    }
}

/**
 * @description: 获取当前系统时间
 * @return {*}
 */
static uio32_t io_tick_get(void)
{
    uio32_t result;
    do
    {
        tick_irq_flag = 1;
        result = sys_time;
    } while (!tick_irq_flag);
    return result;
}

/**
 * @description: 注册设备
 * @param {io_device_t} *dev
 * @return {*}
 */
void io_device_register(io_device_t *dev)
{
    if (dev && device_count < DEVICE_MAX)
    {
        dev_table[device_count++] = dev;
        io_device_init(dev);
        dev->drv->io_disable();
    }
    else
    {
        PRINT_ERR("device register failed");
    }
}

/**
 * @LastEditTime: Do not edit
 * @Description: 设备轮询任务，在主函数中循环
 * @return {}
 */
void io_device_task(void)
{
    uio8_t i = 0;
    for (i = 0; i < device_count; i++)
    {
        io_run_function(dev_table[i]);
    }
}

/**
 * @description: io输出参数设置
 * @param {io8_t} *name
 * @param {uio16_t} enable_ms
 * @param {uio16_t} disable_ms
 * @param {uio16_t} loop_count
 * @param {uio16_t} wait_ms
 * @return {*}
 */
void io_set_param(const io8_t *name, uio16_t enable_ms, uio16_t disable_ms, uio16_t loop_count, uio16_t wait_ms)
{
    io_operation_t *d;

    /* 查找对应设备 找不到退出  */
    d = io_device_found(name);
    if (d == io_ptr)
    {
    }
    else
    {
        /* 设置开启时间 关闭时间 循环次数 延时等待时间 */
        d->enable_time = enable_ms;
        d->disable_time = disable_ms;
        d->loop_count = loop_count;
        d->wait_time = wait_ms;

        /* 获取当前时间戳 */
        d->last_tick = io_tick_get();
        /* 清除当前已完成的循环次数 */
        d->current_count = 0;
        /* 先判断是不是停止输出 */
        if (d->loop_count == IO_OUTPUT_STOP)
        {
            d->state = IO_IDEL;
            d->io_open = IO_FALSE;
            d->io_disable();
        }
        else
        {
            if (d->wait_time > 0)
            {
                d->state = IO_WAIT_START;
                d->io_open = IO_TRUE;
            }
            else
            {
                d->state = IO_ENABLE;
                d->io_open = IO_TRUE;
                d->io_enable();
            }
        }
    }
}

/**
 * @description: 设置对应io电平；无法提供系统时基时使用
 * @param {io8_t} *name
 * @param {uio8_t} new_level
 * @return {*}
 */
void io_set_level(const io8_t *name, uio8_t new_level)
{
    io_operation_t *d;

    /* 查找对应设备 找不到退出  */
    d = io_device_found(name);
    if (d == io_ptr)
    {
        return;
    }
    if (new_level)
    {
        d->io_enable();
    }
    else
    {
        d->io_disable();
    }
}

/**
 * @description: io设备提供实际，在定时器中调用
 * @return {*}
 */
void io_tick_inc(void)
{
    tick_irq_flag = 0;
    sys_time += (IO_TICKS_PERIOD / IO_TICKS_PERIOD);
}
